package com.ggb.reactive.controller.admin

import com.ggb.reactive.constant.*
import com.ggb.reactive.domain.dto.OrdersCancelDTO
import com.ggb.reactive.domain.dto.OrdersConfirmDTO
import com.ggb.reactive.domain.dto.OrdersPageQueryDTO
import com.ggb.reactive.domain.dto.OrdersRejectionDTO
import com.ggb.reactive.domain.entity.Orders
import com.ggb.reactive.domain.vo.OrderStatisticsVO
import com.ggb.reactive.domain.vo.OrderSubmitVO
import com.ggb.reactive.domain.vo.OrderVO
import com.ggb.reactive.extension.log
import com.ggb.reactive.model.PageResult
import com.ggb.reactive.model.Result
import com.ggb.reactive.repository.OrderDetailRepository
import com.ggb.reactive.repository.OrderRepository
import com.ggb.reactive.service.OrderDetailService
import com.ggb.reactive.service.OrderService
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import lombok.RequiredArgsConstructor
import org.springframework.beans.BeanUtils
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.math.BigDecimal
import java.math.RoundingMode
import java.time.Instant

@RestController("adminOrderController")
@RequestMapping("/admin/order")
@Tag(name = "管理端-订单管理")
@RequiredArgsConstructor
class OrderController(
    val orderService: OrderService,
    val orderDetailService: OrderDetailService,
    val orderRepository: OrderRepository
) {


    /**
     *  status 订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
     */
    @GetMapping("/conditionSearch")
    @Operation(summary = "订单搜索")

    fun conditionSearch(ordersPageQueryDTO: OrdersPageQueryDTO): Mono<Result<PageResult<OrderVO>>> {
        return orderService.findOrdersByCriteria(ordersPageQueryDTO)
            .flatMap { page ->
                Flux.fromIterable(page.records!!)
                    .flatMap { order ->
                        orderDetailService.findAllByOrderId(order.id!!)
                            .collectList()
                            .map { details ->
                                val orderVO = OrderVO()

                                BeanUtils.copyProperties(order, orderVO)
                                orderVO.orderDetailList = details
                                orderVO.orderDishes = details.joinToString(separator = ";") {
                                    "${it.name}${it.number}"
                                }
                                orderVO
                            }
                    }
                    .collectList()
                    .map { orderVOs ->
                        Result.success(PageResult(total = page.total, records = orderVOs))
                    }
            }

    }

    @GetMapping("/details/{id}")
    @Operation(summary = "查询订单详情")
    fun detail(@PathVariable id: Long): Mono<Result<OrderVO>> {
        return orderRepository.findById(id)
            .flatMap { order ->
                orderDetailService.findAllByOrderId(order.id!!)
                    .collectList()
                    .map { details ->
                        val orderVO = OrderVO()
                        BeanUtils.copyProperties(order, orderVO)
                        orderVO.orderDetailList = details
                        orderVO.orderDishes = details.joinToString(separator = ";") {
                            "${it.name}${it.number}"
                        }
                        orderVO
                    }
            }
            .map {
                Result.success(it)
            }
    }

    @GetMapping("/statistics")
    @Operation(summary = "各个状态的订单数量统计")
    fun statistics(): Mono<Result<OrderStatisticsVO>> {
        return orderRepository.countByStatus(TO_BE_CONFIRMED)
            .zipWith(orderRepository.countByStatus(CONFIRMED))
            .zipWith(orderRepository.countByStatus(DELIVERY_IN_PROGRESS))
            .map {
                Result.success(
                    OrderStatisticsVO(
                        toBeConfirmed = it.t1.t1,
                        confirmed = it.t1.t2,
                        deliveryInProgress = it.t2
                    )
                )
            }
    }


    @PutMapping("/confirm")
    @Operation(summary = "接单")
    fun repetition(@RequestBody @Validated ordersConfirmDTO: OrdersConfirmDTO): Mono<Result<String>> {
        val order = Orders()
        BeanUtils.copyProperties(ordersConfirmDTO, order)
        order.status = CONFIRMED
        return orderService.updateOrder(order)
            .filter { it > 0 }
            .map {
                Result.success(ACTION_SUCCESS)
            }
            .switchIfEmpty(Mono.just(Result.error(ACTION_FAIL)))
    }

    @PutMapping("/rejection")
    @Operation(summary = "拒单")
    fun rejection(@RequestBody @Validated ordersRejectionDTO: OrdersRejectionDTO): Mono<Result<String>> {
        return orderRepository.findById(ordersRejectionDTO.id!!)
            .flatMap {
                if (it == null || it.status == TO_BE_CONFIRMED) {
                    Mono.just(Result.error(ORDER_STATUS_ERROR))
                } else {
                    val order = Orders()
                    order.id = it.id
                    order.status = CANCELLED
                    order.rejectionReason = ordersRejectionDTO.rejectionReason
                    order.cancelTime = Instant.now()
                    orderService.updateOrder(order).then(
                        Mono.just(Result.success(ACTION_SUCCESS))
                    )
                }
            }
    }

    @PutMapping("/cancel")
    @Operation(summary = "取消订单")
    fun cancel(@RequestBody @Validated ordersCancelDTO: OrdersCancelDTO): Mono<Result<String>> {
        return orderRepository.findById(ordersCancelDTO.id!!)
            .flatMap {
                if (it == null) {
                    Mono.just(Result.error(ORDER_STATUS_ERROR))
                } else {
                    val order = Orders()
                    order.id = it.id
                    order.status = CANCELLED
                    order.cancelReason = ordersCancelDTO.cancelReason
                    order.cancelTime = Instant.now()
                    orderService.updateOrder(order).then(
                        Mono.just(Result.success(ACTION_SUCCESS))
                    )
                }
            }
    }

    @PutMapping("/delivery/{id}")
    @Operation(summary = "派送订单")
    fun delivery(@PathVariable id: Long): Mono<Result<String>> {
        return orderRepository.findById(id)
            .flatMap {
                if (it == null || it.status != CONFIRMED) {
                    Mono.just(Result.error(ORDER_STATUS_ERROR))
                } else {
                    val order = Orders()
                    order.id = it.id
                    order.status = DELIVERY_IN_PROGRESS
                    orderService.updateOrder(order).then(
                        Mono.just(Result.success(ACTION_SUCCESS))
                    )
                }
            }
    }

    @PutMapping("/complete/{id}")
    @Operation(summary = "完成订单")
    fun complete(@PathVariable id: Long): Mono<Result<String>> {
        return orderRepository.findById(id)
            .flatMap {
                if (it == null || it.status != DELIVERY_IN_PROGRESS) {
                    Mono.just(Result.error(ORDER_STATUS_ERROR))
                } else {
                    val order = Orders()
                    order.id = it.id
                    order.status = COMPLETED
                    order.deliveryTime = Instant.now()
                    orderService.updateOrder(order).then(
                        Mono.just(Result.success(ACTION_SUCCESS))
                    )
                }
            }
    }


}